home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / nasanets.zip / PROP.C < prev    next >
C/C++ Source or Header  |  1990-06-07  |  35KB  |  824 lines

  1. /*=============================*/
  2. /*           NETS              */
  3. /*                             */
  4. /* a product of the AI Section */
  5. /* NASA, Johnson Space Center  */
  6. /*                             */
  7. /* principal author:           */
  8. /*       Paul Baffes           */
  9. /*                             */
  10. /* contributing authors:       */
  11. /*      Bryan Dulock           */
  12. /*      Chris Ortiz            */
  13. /*=============================*/
  14.  
  15.  
  16. /*
  17. ----------------------------------------------------------------------
  18.   Code For Forward and Backward Propagation in NETS (Prefix = P_)
  19. ----------------------------------------------------------------------
  20.   This code is divided into 3 major sections:
  21.  
  22.   (1) include files
  23.   (2) externed functions
  24.   (3) subroutines
  25.  
  26.   Each section is further explained below.
  27. ----------------------------------------------------------------------
  28. */
  29.  
  30.  
  31. /*
  32. ----------------------------------------------------------------------
  33.   INCLUDE FILES
  34. ----------------------------------------------------------------------
  35. */
  36. #include "common.h"
  37. #include "weights.h"
  38. #include "layer.h"
  39. #include "net.h"
  40.  
  41.  
  42. /*
  43. ----------------------------------------------------------------------
  44.   EXTERNED FUNCTIONS
  45. ----------------------------------------------------------------------
  46.   Below are the functions defined in other files which are used by the
  47.   code here. They are organized by section.
  48. ----------------------------------------------------------------------
  49. */
  50. extern  Sint         A_activation();
  51. extern  Sint         C_float_to_Sint();
  52.  
  53.  
  54. /*
  55. ======================================================================
  56.   ROUTINES IN PROP.C                                                   
  57. ======================================================================
  58.   The routines in this file are grouped below by function.  Each routine
  59.   is prefixed by the string "P_" indicating that it is defined in the 
  60.   "prop.c" file.  The types returned by the routines are also shown here
  61.   so that cross checking is more easily done between these functions
  62.   and the other files which intern them.
  63.  
  64.  
  65.   Type Returned                 Routine
  66.   -------------                 -------
  67.     void                        P_prop_input
  68.     D_Sint                      P_full_dot_forward
  69.     D_Sint                      P_full_dot_backward
  70.     void                        P_full_update_wts
  71.     D_Sint                      P_s_pattern_dot_forward
  72.     D_Sint                      P_s_pattern_dot_backward
  73.     void                        P_s_pattern_update_wts
  74.     void                        P_prop_error
  75.     Sint                        P_calc_delta
  76.     D_Sint                      P_t_pattern_dot_forward
  77.     D_Sint                      P_t_pattern_dot_backward
  78.     void                        P_t_pattern_update_wts
  79.     void                        P_change_biases
  80. ======================================================================
  81. */
  82.  
  83.  
  84. void  P_prop_input(ptr_net)
  85. Net  *ptr_net;
  86. /*
  87. ----------------------------------------------------------------------
  88.  This routine is definitely NOT going to appear obvious to you the    
  89.   first time you read it.  To understand how it works, or even why I  
  90.   wrote the code the way I have, requires an intimate understanding of
  91.   the Rummelhart paper, the structures I have set up, and the inner   
  92.   workings of integer and pointer arithmetic.  I will assume that the 
  93.   reader has either already read or has access to the Rummelhart paper
  94.   and the '.h' files containing the structures.  As the algorithm is  
  95.   explained, I will make references to the various elements from these
  96.   two sources.                                                        
  97.  Forward propagation, as explained in the paper, is the process of    
  98.   calculating the outputs for the nodes of all layers.  This process  
  99.   is somewhat recursive, in that some layers depend upon the outputs  
  100.   of other layers being calculated first.  Thus the order of layer    
  101.   calculation is important, and this order is presumed to be pre-set  
  102.   by the user within the net configuration file (see doc with the     
  103.   'B_setup_net' routine above and with 'PS_get_layer' in netio.c). The  
  104.   first while loop below takes care of looping through the layers in  
  105.   the correct order (which must be FORWARD since this is forward      
  106.   propagation; see doc for net struc in 'net.h' and for Layer_lst in  
  107.   'layer.h').                                                         
  108.  Now, for each of the layers, we want to figure out the output of each
  109.   of its nodes (target_nodes).  First, we get access to that layers   
  110.   array of node outputs (via cur_layer->value->node_outputs) and then 
  111.   we record (in target_size) how many nodes the layer has (via        
  112.   cur_layer->value->num_nodes).  The first 'for' loop takes care of   
  113.   looping through each of the nodes, in turn, to calculate its output.
  114.  As described by Rummelhart, the output of a node is defined as the   
  115.   dot product between its input layer and the weights connecting the  
  116.   members of that layer to the node in question.  Since we have       
  117.   allowed for the general case of multiple incoming layers, we need   
  118.   another loop to make sure all inputs are processed.  Referring to   
  119.   the layer structure (see layer.h), note that the incoming layers    
  120.   are accessible only through the weights connecting the two layers.  
  121.   (see Layer.in_weights).  Thus we access the incoming weights via    
  122.   cur_layer->value->num_nodes, through which we will be able to get at
  123.   each incoming layer, in turn.  The second while loop serves to loop 
  124.   through each of the incoming weights (or layers).                   
  125.  Now, a weight has a pointer to both its source and target layers, but
  126.   we are only concerned with the source here since it is the incoming 
  127.   layer.  Thus we access the source layer's node outputs (via         
  128.   cur_weight->value->source_layer->node_outputs) and also its size    
  129.   (via cur_weight->value->source_layer->num_nodes).  To multiply these
  130.   outputs by the corresponding weights, we access the weights between 
  131.   the layers (via cur_weight->value->values).                         
  132.  Then, we call 'dot_product' to do the actual multiplications.  The   
  133.   reason to separate this routine out is because it can be optimized  
  134.   even further in assembly code, and we want to leave that option     
  135.   available.                                                          
  136.  Note that we have the statement 'cur_weight += (j * source_size)'    
  137.   immediately preceding the call to the f_prop code.  This bizzare incr 
  138.   statement right in the middle of things is not obvious; its roots   
  139.   are directly linked to our weigts design choice.  Remember that we  
  140.   decided to store the weights in a column major fashion, or more     
  141.   simply, by source rather than by target.  Thus, if we had two       
  142.   layers, s = source and t = target, then our weights array would be  
  143.   ordered as follows:                                                 
  144.                                                                       
  145.    s1,t1 s2,t1 sN,t1   s1,t2 s2,t2 sN,t2   s1,tN s2,tN sN,tN          
  146.                                                                       
  147.   Keep in mind that the trick here is to be able to associate the     
  148.   correct weights with any given source,target pair.  Assuming that   
  149.   are steping down the nodes of a source layer IN ORDER we have no    
  150.   great problems, since the weights are ordered to match the source   
  151.   layer nodes.  For example, if we are currently using s1 and t2, our 
  152.   weight between them is s1,t2.  Steping to the weight between s2 and 
  153.   t2 (to s2,t2) is a simple increment.                                
  154.  However, the problem is not so simple when you are steping through   
  155.   the target layer node by node.  Here each increment in number is    
  156.   paralleled by a SOURCE SIZE JUMP IN THE WEIGHTS ARRAY.  Stated      
  157.   another way, the distance between sX,tY and sX,tY+1 is exactly equal
  158.   to the size of the source layer.  Thus, before we call the routine  
  159.   pointed to by f_prop we must make sure the weights array pointer is   
  160.   set to the proper place for the target represented by "j".  This is 
  161.   done by multiplying 'j' by SOURCE_SIZE and adding the result to the 
  162.   weights pointer.                                                     
  163. ----------------------------------------------------------------------
  164. */
  165. BEGIN
  166.    register Sint  *target_nodes, *target_bias;
  167.    Layer_lst    *cur_layer;
  168.    Weights_lst  *cur_weight;
  169.    D_Sint       sum;
  170.    int          target_size, j;
  171.   
  172.    cur_layer = ptr_net->hidden_front;
  173.    while (cur_layer != NULL) BEGIN
  174.       target_nodes = cur_layer->value->node_outputs;
  175.       target_bias  = cur_layer->value->node_bias;
  176.       target_size  = cur_layer->value->num_nodes;
  177.  
  178.       for (j = 0; j < target_size; j++) BEGIN
  179.          sum = 0;
  180.          cur_weight = cur_layer->value->in_weights;
  181.          while (cur_weight != NULL) BEGIN
  182.             sum = (*cur_weight->value->f_prop) (sum, cur_weight->value, j);
  183.             cur_weight = cur_weight->next;
  184.          ENDWHILE
  185.          *target_nodes++ = A_activation(sum + (*target_bias++));
  186.       ENDFOR
  187.       cur_layer = cur_layer->next;
  188.    ENDWHILE
  189.  
  190. END /* P_prop_input */
  191.  
  192.  
  193. D_Sint  P_full_dot_forward(cur_total, the_weights, t_node_index)
  194. D_Sint   cur_total;
  195. Weights  *the_weights;
  196. int      t_node_index;
  197. /*
  198. ----------------------------------------------------------------------
  199. connect-all
  200.  Finally we are ready to form the dot product between a set of outputs
  201.   and the corresponding weights.  Since all of the weights between    
  202.   two layers are stored together, we must choose only those weights   
  203.   which are connected to the node in the target layer (ie, node j)    
  204.   which we are currently handling.  Additionally, we must use exactly 
  205.   as many weights as we have nodes in the source layer (source_size). 
  206.   Happily, we knew this would be the case, thus we ordered the weights
  207.   between two layers BY TARGET LAYER NUMBER.  Thus, all of node j's   
  208.   weights come before those of node j+1, etc. (see doc in weights.c   
  209.   for 'S_show_weights').  This routine takes care of doing just 'num' 
  210.   number of multiplications.                                          
  211.  Notice, however, that while I define variable i to determine         
  212.   the correct number of times to loop, I NEVER USE THE VARIABLE in    
  213.   an array access.  This is because an array access is an inheirantly 
  214.   slow calculation.  Instead, we rely on the fact that the arrays we  
  215.   are dealing with have all of their information stored sequentially, 
  216.   so we can just increment the pointer to the array to move from      
  217.   element to element.  The i  variable is used only to indicate       
  218.   how many times the loop should be done.    
  219.  Note that the indexing of the weights and nodes arrays depends upon
  220.   the connection scheme. In the CONNECT_ALL case, we have very little 
  221.   complication as everything is interconnected. In the PATTERNED case,
  222.   I make use of a trick in which I write TWO loops, one the size of the
  223.   smaller layer, and then increment the pointer from the smaller layer
  224.   each time the INNER loop finishes. This way I can avoid one set of
  225.   array accesses (ie, to the smaller layer). The larger layer I must still
  226.   access using array notation via the "decoder" array (see 'weights.h').
  227.  Finally, remember that we are dotting  SOURCE layer with the weights,
  228.   thus every time we increment the source by one, we must increment   
  229.   the weights by one to keep the weights and source numbers the same. 
  230.   (see documentation under 'P_prop_inputs'). Also, since each Sint is
  231.   actually an integer representation with an implied decimal point, we
  232.   have the result that after our dot product is formed we have incidentally
  233.   multiplied it by a constant factor of SINT_SCALE. That is, each time we
  234.   do a multiplication of two Sints, we end up with an extra factor of
  235.   SINT_SCALE. Thus we must divide this out before returning the value.
  236.   Of course, this does not hold when floats are used rather than Sints.
  237.   Lastly, note that we disallow any value which exceeds the maximum or
  238.   minimum Sint value. This keeps the overall node value from exceeding
  239.   its maximum (note that no intermediate product will exceed the maximum
  240.   since the node values are between 0 and 1 and since only 10000 nodes
  241.   are allowed per layer).
  242. ----------------------------------------------------------------------
  243.  This routine has been further divided into three replicas. By separating
  244.  the three different ways of propagating forward, I can speed the 
  245.  learning process by avoiding "if" checking to see whether or not I
  246.  should use patterened connection schemes or a connect-all scheme. The
  247.  result is that I have to store a pointer to this function INSIDE THE
  248.  WEIGHTS STRUCTURES THAT USE IT (change made 9-5-89). This first routine
  249.  is for fully connected schemes only.
  250. ----------------------------------------------------------------------
  251. */
  252. BEGIN
  253.    register Sint   *ptr_Snodes, *ptr_weights;
  254.    int             i, s_size;
  255.  
  256.    s_size      = the_weights->source_layer->num_nodes;
  257.    ptr_Snodes  = the_weights->source_layer->node_outputs;
  258.    ptr_weights = the_weights->values + (t_node_index * s_size);
  259.  
  260.    for (i = 0; i < s_size; i++)
  261.       cur_total += ((D_Sint)(*ptr_Snodes++) * (D_Sint)(*ptr_weights++));
  262.  
  263. #if  USE_SCALED_INTS
  264.    return(cur_total / (D_Sint)SINT_SCALE);
  265. #else
  266.    return(cur_total);
  267. #endif
  268.    
  269. END /* P_full_dot_forward */
  270.  
  271.  
  272. D_Sint  P_s_pattern_dot_forward(cur_total, the_weights, t_node_index)
  273. D_Sint   cur_total;
  274. Weights  *the_weights;
  275. int      t_node_index;
  276. /*
  277. ----------------------------------------------------------------------
  278.   (see documentation under P_full_dot_forward) This routine is for 
  279.   pattern connection schemes which have a large source layer connected
  280.   to a smaller target layer.
  281. ----------------------------------------------------------------------
  282. */
  283. BEGIN
  284.    register Sint   *ptr_Snodes, *ptr_weights;
  285.    register int16  *ptr_decoder;
  286.    int             i, area;
  287.  
  288.    area        = the_weights->map_area;
  289.    ptr_Snodes  = the_weights->source_layer->node_outputs;
  290.    ptr_weights = the_weights->values + (area * t_node_index);
  291.    ptr_decoder = the_weights->decoder + (area * t_node_index);
  292.  
  293.    for (i = 0; i < area; i++)
  294.       cur_total += ((D_Sint)(ptr_Snodes[*ptr_decoder++])
  295.                     * (D_Sint)(*ptr_weights++));
  296.  
  297. #if  USE_SCALED_INTS
  298.    return(cur_total / (D_Sint)SINT_SCALE);
  299. #else
  300.    return(cur_total);
  301. #endif
  302.    
  303. END /* P_s_pattern_dot_forward */
  304.  
  305.  
  306. D_Sint  P_t_pattern_dot_forward(cur_total, the_weights, t_node_index)
  307. D_Sint   cur_total;
  308. Weights  *the_weights;
  309. int      t_node_index;
  310. /*
  311. ----------------------------------------------------------------------
  312.   (see documentation under P_full_dot_forward) This routine is for 
  313.   pattern connection schemes which have a large target layer connected
  314.   to a smaller source layer.
  315. ----------------------------------------------------------------------
  316. */
  317. BEGIN
  318.    register Sint   *ptr_Snodes, *ptr_weights;
  319.    register int16  *ptr_decoder;
  320.    int             i, j, s_size, area;
  321.  
  322.    s_size      = the_weights->source_layer->num_nodes;
  323.    ptr_Snodes  = the_weights->source_layer->node_outputs;
  324.    ptr_weights = the_weights->values;
  325.    area        = the_weights->map_area;
  326.    ptr_decoder = the_weights->decoder;
  327.  
  328.    for (i = 0; i < s_size; i++) BEGIN
  329.       for (j = 0; j < area; j++) BEGIN
  330.          if (*ptr_decoder == t_node_index)
  331.             cur_total += ((D_Sint)(*ptr_Snodes)
  332.                           * (D_Sint)(*ptr_weights));
  333.          ptr_decoder++;
  334.          ptr_weights++;
  335.       ENDFOR
  336.       ptr_Snodes++;
  337.    ENDFOR
  338.  
  339. #if  USE_SCALED_INTS
  340.    return(cur_total / (D_Sint)SINT_SCALE);
  341. #else
  342.    return(cur_total);
  343. #endif
  344.    
  345. END /* P_t_pattern_dot_forward */
  346.  
  347.  
  348. void  P_prop_error(ptr_net)
  349. Net  *ptr_net;
  350. /*
  351. ----------------------------------------------------------------------
  352.  Similar to P_prop_input, only you propagate backwards.  Instead of     
  353.   propagating outputs, however, you calculate DELTA values which are  
  354.   a measure of how much error should be propagated back through a     
  355.   particular node (see Rummelhart paper).  Thus, you start with the   
  356.   'hidden_back' pointer, and move back through the list using 'prev'  
  357.   pointers (instead of 'next'), calculating deltas as you go.  One    
  358.   other difference here is that you DO NOT have to waste any time     
  359.   propagating deltas back to layer 0, since by definition it does not 
  360.   have any incoming weights.  That is, since the deltas are only      
  361.   needed for changing weight values, and since weights are changed    
  362.   from target to source layers (see Rummelhart paper), there is no    
  363.   need for delta values in a layer which  never acts as a target.     
  364.   Layer 0 (the input) is such a layer.                                
  365. ----------------------------------------------------------------------
  366. */
  367. BEGIN
  368.    register Sint  *source_deltas, *source_nodes;
  369.    Layer_lst    *cur_layer;
  370.    Weights_lst  *cur_weight;
  371.    Sint         output, P_calc_delta();
  372.    D_Sint       sum;
  373.    int          source_size, j;
  374.   
  375.    cur_layer = ptr_net->hidden_back;
  376.    while (cur_layer != NULL) BEGIN
  377.       if (cur_layer->value->ID == 0) break;      /* dont do for layer 0 */
  378.       source_nodes  = cur_layer->value->node_outputs;
  379.       source_deltas = cur_layer->value->node_deltas;
  380.       source_size   = cur_layer->value->num_nodes;
  381.       for (j = 0; j < source_size; j++) BEGIN
  382.          sum = 0;
  383.          cur_weight = cur_layer->value->out_weights;
  384.          while (cur_weight != NULL) BEGIN
  385.             sum = (*cur_weight->value->b_prop) (sum, cur_weight->value, j);
  386.             cur_weight = cur_weight->next;
  387.          ENDWHILE
  388.          output = *source_nodes++;
  389.          *source_deltas++ = P_calc_delta(sum, output); 
  390.       ENDFOR
  391.       cur_layer = cur_layer->prev;
  392.    ENDWHILE
  393.  
  394. END /* P_prop_error */
  395.  
  396.  
  397. D_Sint  P_full_dot_backward(cur_total, the_weights, s_node_index)
  398. D_Sint   cur_total;
  399. Weights  *the_weights;
  400. int      s_node_index;
  401. /*
  402. ----------------------------------------------------------------------
  403.  This routine is almost identical to the '...dot_forward' routines above. 
  404.   Note that we pass in a second argument, "s_size", to this routine   
  405.   because of how we must increment the weights pointer to keep it in  
  406.   sync with the target pointer.  That is, every time we increment the 
  407.   the target pointer by one, we must increment the weights pointer by 
  408.   SOURCE size (see documentation under 'P_prop_input'). 
  409.  NOTE that we are propagating back from the TARGET layer to the SOURCE
  410.   layer.
  411. ----------------------------------------------------------------------
  412.  I split this routine into three parts as I did for P_full_dot_forward
  413.   above (see above documentation). This first version is for fully 
  414.   connected schemes.
  415. ----------------------------------------------------------------------
  416. */
  417. BEGIN
  418.    register Sint   *ptr_Tdeltas, *ptr_weights;
  419.    register int    i, s_size, t_size;
  420.  
  421.    s_size      = the_weights->source_layer->num_nodes;
  422.    t_size      = the_weights->target_layer->num_nodes;
  423.    ptr_Tdeltas = the_weights->target_layer->node_deltas;
  424.    ptr_weights = the_weights->values + s_node_index;
  425.    
  426.    for (i = 0; i < t_size; i++) BEGIN
  427.       cur_total += ((D_Sint)(*ptr_Tdeltas++) * (D_Sint)(*ptr_weights));
  428.       ptr_weights += s_size;
  429.    ENDFOR
  430.  
  431. #if  USE_SCALED_INTS
  432.    return(cur_total / (D_Sint)SINT_SCALE);
  433. #else
  434.    return(cur_total);
  435. #endif
  436.  
  437. END /* P_full_dot_backward */
  438.  
  439.  
  440. D_Sint  P_s_pattern_dot_backward(cur_total, the_weights, s_node_index)
  441. D_Sint   cur_total;
  442. Weights  *the_weights;
  443. int      s_node_index;
  444. /*
  445. ----------------------------------------------------------------------
  446.  (see documentation under P_full_dot_backward and P_full_dot_forward).
  447.   This is the back propagation for weights which connect large source
  448.   layers to smaller target layers.
  449. ----------------------------------------------------------------------
  450. */
  451. BEGIN
  452.    register Sint   *ptr_Tdeltas, *ptr_weights;
  453.    register int16  *ptr_decoder;
  454.    int             i, j, t_size, area;
  455.  
  456.    t_size      = the_weights->target_layer->num_nodes;
  457.    ptr_Tdeltas = the_weights->target_layer->node_deltas;
  458.    ptr_weights = the_weights->values;
  459.    area        = the_weights->map_area;
  460.    ptr_decoder = the_weights->decoder;
  461.       
  462.    for (i = 0; i < t_size; i++) BEGIN
  463.       for (j = 0; j < area; j++) BEGIN
  464.          if (*ptr_decoder == s_node_index)
  465.             cur_total += ((D_Sint)(*ptr_Tdeltas) 
  466.                           * (D_Sint)(*ptr_weights));
  467.          ptr_decoder++;
  468.          ptr_weights++;
  469.       ENDFOR
  470.       ptr_Tdeltas++;
  471.    ENDFOR
  472.  
  473. #if  USE_SCALED_INTS
  474.    return(cur_total / (D_Sint)SINT_SCALE);
  475. #else
  476.    return(cur_total);
  477. #endif
  478.  
  479. END /* P_s_pattern_dot_backward */
  480.  
  481.  
  482. D_Sint  P_t_pattern_dot_backward(cur_total, the_weights, s_node_index)
  483. D_Sint   cur_total;
  484. Weights  *the_weights;
  485. int      s_node_index;
  486. /*
  487. ----------------------------------------------------------------------
  488.  (see documentation under P_full_dot_backward and P_full_dot_forward).
  489.   This is the back propagation for weights which connect large target
  490.   layers to smaller source layers.
  491. ----------------------------------------------------------------------
  492. */
  493. BEGIN
  494.    register Sint   *ptr_Tdeltas, *ptr_weights;
  495.    register int16  *ptr_decoder;
  496.    int             i, area;
  497.  
  498.    area        = the_weights->map_area;
  499.    ptr_Tdeltas = the_weights->target_layer->node_deltas;
  500.    ptr_weights = the_weights->values + (area * s_node_index);
  501.    ptr_decoder = the_weights->decoder + (area * s_node_index);
  502.    
  503.    for (i = 0; i < area; i++)
  504.       cur_total += ((D_Sint)(ptr_Tdeltas[*ptr_decoder++])
  505.                     * (D_Sint)(*ptr_weights++));
  506.  
  507. #if  USE_SCALED_INTS
  508.    return(cur_total / (D_Sint)SINT_SCALE);
  509. #else
  510.    return(cur_total);
  511. #endif
  512.  
  513. END /* P_t_pattern_dot_backward */
  514.  
  515.  
  516. Sint  P_calc_delta(error_sum, output)
  517. D_Sint  error_sum;
  518. Sint    output;
  519. /*
  520. ----------------------------------------------------------------------
  521.  This little routine computes the DELTA value for the node, given two 
  522.   inputs:  an error sum (or just an error difference for the output   
  523.   nodes), and an output value for the node.  The formula for computing
  524.   the delta value is:  [ error_sum * output * (1 - output) ].  This   
  525.   would be no hard computation, except for the fact that we have a    
  526.   special SCALED representation for our incoming arguments, namely the
  527.   'Sint' type.  Thus, we cannot just use the '1' in the above formula 
  528.   since that number is in decimal, not in Sint form.  Also, because   
  529.   our scaled integers are all multiplied by a common factor, every    
  530.   we multiply two Sints together, we get a result which has that      
  531.   that common factor TO A POWER OF TWO!  For example, the Sint = 1 is 
  532.   1024 (also called SINT_SCALE).  If we multiply it by itself, we     
  533.   will get 1,048,576; however, the corresponding decimal product would
  534.   be 1 * 1 = 1, or 1024 in Sint!!! Thus, we must always divide each   
  535.   multiplication of a Sint by 1024 so that our result is correct.     
  536.  Note that this routine makes use of the D_Sint type, which is just   
  537.   a Sint which is twice as big in the machine.  The reason for this is
  538.   that multiplication of two Sints could lead to a result which is    
  539.   larger than a Sint type can hold; by using the D_Sint we ensure that
  540.   no intermediate results will be out of range.                       
  541.  Note also that the error_sum argument comes in as a D_Sint, not a    
  542.   Sint.  In the routine above, a type conversion has to be made for   
  543.   the types to match.  Doesn't that seem odd? Actually, the answer for
  544.   why this is done does not become apparent until you understand the  
  545.   P_prop_error routine below.  It turns out that the general case of    
  546.   calculating a delta for a given node will involve an error_sum of   
  547.   all the error effects from target layers.  This sum involves a      
  548.   product of two Sints and as such must be stored in a D_Sint if we   
  549.   want to avoid overflows during the multiplication.  Thus, this      
  550.   routine expects that the error_sum will come in as a D_Sint, thus   
  551.   the code above must make a type conversion to remain compatible.    
  552. ----------------------------------------------------------------------
  553. */
  554. BEGIN
  555. #if  USE_SCALED_INTS
  556.    D_Sint  temp;
  557.  
  558.    temp = (error_sum * (D_Sint)output) / SINT_SCALE;
  559.    temp = (temp * (D_Sint)(SINT_SCALE - output)) / SINT_SCALE;
  560.    return((Sint) temp);
  561. #else
  562.    return( (Sint)(error_sum * output * (1.0 - output)) );
  563. #endif
  564.  
  565. END /* P_calc_delta */
  566.  
  567.  
  568. void  P_full_update_wts(source, target, the_weights)
  569. Layer    *source, *target;
  570. Weights  *the_weights;
  571. /*
  572. ----------------------------------------------------------------------
  573.  This code follows the same rules for steping through a set of weights
  574.   that both the 'dot_forward' and 'dot_backward' routines had to      
  575.   follow.  Because the weights are stored by source size (column      
  576.   major) each increment of source number increments the weights by one
  577.   and each increment of target number increments the weights by the   
  578.   source size (see P_prop_inputs doc.).  Thus, in order to step through 
  579.   the weights one at a time and keep the source and target pointers   
  580.   in sync, I put the target incrementation as the OUTTER loop and the 
  581.   source incrementation as the INNER loop, for the CONNECT_ALL case. I
  582.   can use the same trick in the PATTERNED connection case, and it will
  583.   always refer to the layer with the fewer number of nodes. In this case,
  584.   I have two loops, one for the size of the smaller layer and an inner one
  585.   for the size of the map_area. Each time the second loop is completed we
  586.   move on to the next element of the smaller layer, and the appropriate
  587.   pointer is incremented.
  588.  Once the correct weight, target delta, and source output are located 
  589.   the code does the weight change calculation shown in Rummelhart.    
  590.   Note once again that because of our Sint format, any products of    
  591.   two Sint values must be divided by SINT_SCALE (see 'P_full_dot_forward'    
  592.   documentation).                                                     
  593.  A change was made here on 3-16-89 to calculate the learning rate 
  594.   dynamically for each IO pair (see T_change_weights and T_setup_errors).
  595. ----------------------------------------------------------------------
  596.  Like P_full_dot_forward and P_full_dot_backward, this routine was split
  597.   into three different functions, one for each type of connection scheme.
  598.   This first version handles weight updates for fully connected weight
  599.   schemes only.
  600. ----------------------------------------------------------------------
  601. */
  602. BEGIN
  603.    register Sint  *source_nodes, *save_source, *target_deltas;
  604.    D_Sint  temp, temp2, learn, momentum;
  605.    int     s_size, i, j;
  606.    Sint    *wt_values, *wt_deltas, new_delta;
  607. #if  USE_SCALED_INTS
  608.    D_Sint  scale;
  609.  
  610.    scale         = (D_Sint)SINT_SCALE;
  611. #endif
  612.    source_nodes  = source->node_outputs;
  613.    save_source   = source_nodes;
  614.    s_size        = source->num_nodes;
  615.    target_deltas = target->node_deltas;
  616.    wt_values     = the_weights->values;
  617.    wt_deltas     = the_weights->prev_deltaW;
  618.    learn         = target->cur_learn;
  619.    momentum      = (D_Sint)C_float_to_Sint(target->momentum);
  620.    
  621.    for (i = 0; i < target->num_nodes; i++) BEGIN
  622.       source_nodes = save_source;
  623. #if  USE_SCALED_INTS
  624.       temp = (learn * (D_Sint)(*target_deltas++)) / scale;
  625.       for (j = 0; j < s_size; j++) BEGIN
  626.          temp2 = (temp * (D_Sint)(*source_nodes++)) / scale;
  627.          temp2 = temp2 + ((momentum * (D_Sint)(*wt_deltas)) / scale);
  628. #else
  629.       temp = (learn * (D_Sint)(*target_deltas++));
  630.       for (j = 0; j < s_size; j++) BEGIN
  631.          temp2 = temp * (D_Sint)(*source_nodes++);
  632.          temp2 = temp2 + (momentum * (D_Sint)(*wt_deltas));
  633. #endif
  634.          new_delta = (Sint)temp2;
  635.          *(wt_deltas++) = new_delta;
  636.          *(wt_values++) += new_delta;
  637.       ENDFOR
  638.    ENDFOR
  639.  
  640. END /* P_full_update_wts */
  641.  
  642.  
  643. void  P_s_pattern_update_wts(source, target, the_weights)
  644. Layer    *source, *target;
  645. Weights  *the_weights;
  646. /*
  647. ----------------------------------------------------------------------
  648.  (see documentation for P_full_update_wts and P_full_dot_backward). 
  649.   This routine updates the weights for patterned connection schemes 
  650.   where the source layer is larger than the target layer.
  651. ----------------------------------------------------------------------
  652. */
  653. BEGIN
  654.    register Sint  *source_nodes, *target_deltas;
  655.    D_Sint  temp, temp2, learn, momentum;
  656.    int     i, j, area;
  657.    Sint    *wt_values, *wt_deltas, new_delta;
  658.    int16   *ptr_decoder;
  659. #if  USE_SCALED_INTS
  660.    D_Sint  scale;
  661.  
  662.    scale         = (D_Sint)SINT_SCALE;
  663. #endif
  664.    source_nodes  = source->node_outputs;
  665.    target_deltas = target->node_deltas;
  666.    wt_values     = the_weights->values;
  667.    wt_deltas     = the_weights->prev_deltaW;
  668.    learn         = target->cur_learn;
  669.    momentum      = (D_Sint)C_float_to_Sint(target->momentum);
  670.    area          = the_weights->map_area;
  671.    ptr_decoder   = the_weights->decoder;
  672.  
  673.    for (i = 0; i < target->num_nodes; i++) BEGIN
  674. #if USE_SCALED_INTS
  675.       temp = (learn * (D_Sint)(*target_deltas++)) / scale;
  676.       for (j = 0; j < area; j++) BEGIN
  677.          temp2 = (temp * (D_Sint)(source_nodes[*ptr_decoder++])) / scale;
  678.          temp2 = temp2 + ((momentum * (D_Sint)(*wt_deltas)) / scale);
  679. #else
  680.       temp = (learn * (D_Sint)(*target_deltas++));
  681.       for (j = 0; j < area; j++) BEGIN
  682.          temp2 = temp * (D_Sint)(source_nodes[*ptr_decoder++]);
  683.          temp2 = temp2 + (momentum * (D_Sint)(*wt_deltas));
  684. #endif
  685.          new_delta = (Sint)temp2;
  686.          *(wt_deltas++) = new_delta;
  687.          *(wt_values++) += new_delta;
  688.       ENDFOR
  689.    ENDFOR
  690.  
  691. END /* P_s_pattern_update_wts */
  692.  
  693.  
  694. void  P_t_pattern_update_wts(source, target, the_weights)
  695. Layer    *source, *target;
  696. Weights  *the_weights;
  697. /*
  698. ----------------------------------------------------------------------
  699.  (see documentation for P_full_update_wts and P_full_dot_backward). 
  700.   This routine updates the weights for patterned connection schemes 
  701.   where the target layer is larger than the source layer.
  702. ----------------------------------------------------------------------
  703. */
  704. BEGIN
  705.    register Sint  *source_nodes, *target_deltas;
  706.    D_Sint  temp, temp2, learn, momentum;
  707.    int     i, j, area;
  708.    Sint    *wt_values, *wt_deltas, new_delta;
  709.    int16   *ptr_decoder;
  710. #if  USE_SCALED_INTS
  711.    D_Sint  scale;
  712.  
  713.    scale         = (D_Sint)SINT_SCALE;
  714. #endif
  715.    source_nodes  = source->node_outputs;
  716.    target_deltas = target->node_deltas;
  717.    wt_values     = the_weights->values;
  718.    wt_deltas     = the_weights->prev_deltaW;
  719.    learn         = target->cur_learn;
  720.    momentum      = (D_Sint)C_float_to_Sint(target->momentum);
  721.    area          = the_weights->map_area;
  722.    ptr_decoder   = the_weights->decoder;
  723.  
  724.    for (i = 0; i < source->num_nodes; i++) BEGIN
  725. #if USE_SCALED_INTS
  726.       temp = (learn * (D_Sint)(*source_nodes++)) / scale;
  727.       for (j = 0; j < area; j++) BEGIN
  728.          temp2 = (temp * (D_Sint)(target_deltas[*ptr_decoder++])) / scale;
  729.          temp2 = temp2 + ((momentum * (D_Sint)(*wt_deltas)) / scale);
  730. #else
  731.       temp = (learn * (D_Sint)(*source_nodes++));
  732.       for (j = 0; j < area; j++) BEGIN
  733.          temp2 = temp * (D_Sint)(target_deltas[*ptr_decoder++]);
  734.          temp2 = temp2 + (momentum * (D_Sint)(*wt_deltas));
  735. #endif
  736.          new_delta = (Sint)temp2;
  737.          *(wt_deltas++) = new_delta;
  738.          *(wt_values++) += new_delta;
  739.       ENDFOR
  740.    ENDFOR
  741.  
  742. END /* P_t_pattern_update_wts */
  743.  
  744.  
  745. void  P_change_biases(ptr_layers)
  746. Layer_lst  *ptr_layers;
  747. /*
  748. ----------------------------------------------------------------------
  749.  The goal of this routine is the updating of the node bias values, 
  750.   similar to the way in which weights are changed. Two new values are
  751.   determined for each node of the network (1) a new bias value (2) the
  752.   amount by which to change the bias value. In fact, as with the weights
  753.   the delta bias (deltaB) is determined based on 
  754.   
  755.      dBias = learn_rate * delta_of_output_node * output_of_input_node
  756.   
  757.   In the bias case, the last element of the product is always = 1.0, so
  758.   it can be dropped out of the calculation. The routine is called after
  759.   all delta values have been computed, thus we only need move through
  760.   the layers in consecutive order making the changes as we go. 
  761.   Note: 
  762. ----------------------------------------------------------------------
  763. */
  764. BEGIN
  765.    register Sint  *cur_bias, *cur_dB, *cur_delta;
  766.    Layer      *cur_layer;
  767.    int        i;
  768.    D_Sint     temp, learn, momentum;
  769.    Sint       new_delta;
  770. #if  USE_SCALED_INTS
  771.    D_Sint     scale;
  772.  
  773.    /*------------------*/
  774.    /* get scale factor */
  775.    /*------------------*/
  776.    scale = (D_Sint)SINT_SCALE;
  777. #endif
  778.  
  779.    while (ptr_layers != NULL) BEGIN
  780.       /*--------------------------*/
  781.       /* access the current layer */
  782.       /*--------------------------*/
  783.       cur_layer = ptr_layers->value;
  784.  
  785.       /*------------------------------------*/
  786.       /* get the learning rate and momentum */
  787.       /*------------------------------------*/
  788.       learn     = cur_layer->cur_learn;
  789.       momentum  = (D_Sint)C_float_to_Sint(cur_layer->momentum);
  790.       
  791.       /*--------------------------*/
  792.       /* get pointers to bias and */
  793.       /* previous deltaB arrays   */
  794.       /*--------------------------*/
  795.       cur_bias  = cur_layer->node_bias;
  796.       cur_delta = cur_layer->node_deltas;
  797.       cur_dB    = cur_layer->prev_deltaB;
  798.       
  799.       /*--------------------------------*/
  800.       /* loop to update both the biases */
  801.       /* and the prev_deltaB values     */
  802.       /*--------------------------------*/
  803.       for (i = 0; i < cur_layer->num_nodes; i++) BEGIN
  804. #if  USE_SCALED_INTS
  805.          temp = (learn * (D_Sint)(*cur_delta++)) / scale;
  806.          new_delta = 
  807.            (Sint)(temp + ((momentum * (D_Sint)(*cur_dB)) / scale));
  808. #else
  809.          temp = learn * (D_Sint)(*cur_delta++);
  810.          new_delta = 
  811.            (Sint)(temp + (momentum * (D_Sint)(*cur_dB)));
  812. #endif
  813.          *cur_dB++     = new_delta;
  814.          *cur_bias++  += new_delta;
  815.       ENDFOR   
  816.       
  817.       /*---------------------*/
  818.       /* go on to next layer */
  819.       /*---------------------*/
  820.       ptr_layers = ptr_layers->next;
  821.    ENDWHILE
  822.    
  823. END /* P_change_biases */
  824.